package dao;

import com.vividsolutions.jts.geom.Point;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import model.PontoGastronomico;
import org.hibernate.Query;
import org.hibernate.Session;
import util.HibernateUtil;

/**
 *
 * @author Lucas S Bueno
 */
public class PontoGastronomicoDAO implements BasicDAOInterface<PontoGastronomico> {

   @Override
   public boolean salvar(PontoGastronomico obj) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();

      try {
         session.save(obj);
         session.getTransaction().commit();
         session.disconnect();
      } catch (Exception e) {
         System.err.println("ERRO AO SALVAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return false;
      }

      return true;
   }

   @Override
   public List<PontoGastronomico> recuperar() {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();
      List<PontoGastronomico> pontosGastronomicos;

      try {
         pontosGastronomicos = session.createQuery("from PontoGastronomico").list();
         session.getTransaction().commit();
      } catch (Exception e) {
         System.err.println("ERRO AO RECUPERAR PONTOS GASTRONOMICOS!\n" + e.getMessage());
         return null;
      }

      return pontosGastronomicos;
   }

   @Override
   public PontoGastronomico recuperar(int id) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();
      PontoGastronomico pontoGastronomico;

      try {
         Query consulta = session.createQuery("from PontoGastronomico as pon where pon.id = :id");
         consulta.setInteger("id", id);
         pontoGastronomico = (PontoGastronomico) consulta.uniqueResult();
         session.getTransaction().commit();
      } catch (Exception e) {
         System.err.println("ERRO AO RECUPERAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return null;
      }

      return pontoGastronomico;
   }

   public List<PontoGastronomico> recuperar(String tiposConcatenados, String estilosConcatenados, Point pontoInicial, int raio, float preco, String descricao, String horaA, String horaF, float avaliacao, boolean aberto) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();
      
      List<PontoGastronomico> pontosGastronomicos;
      StringBuilder query = new StringBuilder("select pon from PontoGastronomico pon join pon.estilos est where");
      boolean and = false;
      boolean showAll = true;      
      double raioPG = (double) raio/100000;
      
      //verificação de tipos
      if (tiposConcatenados != null) {         
         showAll = false;
         and = true;
         
         query.append(" pon.tipo.tipo in (");
         
         String[] tipos = tiposConcatenados.split(",");
         //construcao da string de conjunto de tipos          
         for (int i = 0; i < tipos.length; i++) {
            query.append("'");
            query.append(tipos[i] + "'");            
            
            if (i != tipos.length - 1) {
               query.append(", ");
            }
         }    
         
         query.append(")");        
      }

      //verificação de estilos
      if (estilosConcatenados != null) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" est.estilo in (");
         
         String[] estilos = estilosConcatenados.split(",");
         //construcao da string de conjunto de estilos               
         for (int i = 0; i < estilos.length; i++) {
            query.append("'");
            query.append(estilos[i] + "'");            
            
            if (i != estilos.length - 1) {
               query.append(", ");
            }
         }
         
         query.append(")");                 
      }

      //verificação de distância dos pontos
      if (pontoInicial != null && raio > 0) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" ST_DISTANCE(pon.geolocalizacao, ST_GeomFromText('");
         query.append(pontoInicial.toString());
         query.append("')) < ");
         query.append(raioPG);         
      }

      //verificação de preço
      if (preco > 0) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" pon.precoMedio <= ");
         query.append(preco);
      }

      //verificação de descrição do ponto
      if (descricao != null) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" lower(pon.cardapio) like '%");
         query.append(descricao.toLowerCase());
         query.append("%'");
      }

      //verificação de horário de abertura
      if (horaA != null) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" pon.horaAbre >= '");
         query.append(horaA + "'");
      }
      
      //verificação de horário de fechamento
      if (horaF != null) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" pon.horaFecha <= '");
         query.append(horaF + "'");
      }
      
      //verificação de avaliação
      if (avaliacao > 0) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } else {
            and = true;
         }
         
         query.append(" pon.avaliacaoMedia >= ");
         query.append(avaliacao);
      }
      
      //verificação de horário de funcionamento
      if (aberto) {
         showAll = false;
         
         //verifica se precisa adicionar um and na query
         if (and) {
            query.append(" and");
         } 
         
         query.append(" pon.horaAbre <= current_time and pon.horaFecha >= current_time");
      }      
      
      System.out.println(query);
      Query consulta;
      
      //se não existe nenum filtro, retorna todos os pontos
      if (showAll) {
         consulta = session.createQuery("from PontoGastronomico");
      } else {         
         consulta = session.createQuery(query.toString());
      }
      
      //executa a consulta
      try {
         pontosGastronomicos = consulta.list();
         session.getTransaction().commit();
      } catch (Exception e) {
         System.err.println("ERRO AO RECUPERAR PONTOS GASTRONOMICOS!\n" + e.getMessage());
         return null;
      }
      
      //elimina possíveis duplicatas
      Set<PontoGastronomico> setPontos = new HashSet<PontoGastronomico>(pontosGastronomicos);
      pontosGastronomicos.clear();
      pontosGastronomicos.addAll(setPontos);      
      
      return pontosGastronomicos;
   }

   @Override
   public boolean atualizar(PontoGastronomico obj) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();

      try {
         session.update(obj);
         session.getTransaction().commit();
         session.disconnect();
      } catch (Exception e) {
         System.err.println("ERRO AO ATUALIZAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return false;
      }

      return true;
   }
   
   public boolean atualizar(int id, float gastos, int avaliacao) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();
      PontoGastronomico pontoGastronomico;

      try {
         Query consulta = session.createQuery("from PontoGastronomico as pon where pon.id = :id");
         consulta.setInteger("id", id);
         pontoGastronomico = (PontoGastronomico) consulta.uniqueResult();         
      } catch (Exception e) {
         System.err.println("ERRO AO RECUPERAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return false;
      }      
      
      pontoGastronomico.setAvaliacaoMedia((avaliacao + pontoGastronomico.getAvaliacaoMedia()) / 2);
      pontoGastronomico.setQuantidadeAvaliacoes(pontoGastronomico.getQuantidadeAvaliacoes() + 1);
      pontoGastronomico.setPrecoMedio((gastos + pontoGastronomico.getPrecoMedio()) / 2);
      pontoGastronomico.setQuantidadePrecos(pontoGastronomico.getQuantidadePrecos() + 1);
           
      try {
         session.update(pontoGastronomico);
         session.getTransaction().commit();
         session.disconnect();
      } catch (Exception e) {
         System.err.println("ERRO AO ATUALIZAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return false;
      }

      return true;
   }

   @Override
   public boolean deletar(PontoGastronomico obj) {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();

      try {
         session.delete(obj);
         session.getTransaction().commit();
         session.disconnect();
      } catch (Exception e) {
         System.err.println("ERRO AO DELETAR PONTO GASTRONOMICO!\n" + e.getMessage());
         return false;
      }

      return true;
   }
}
